from django.db import models
from typing import override
from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.contrib.auth.hashers import make_password
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.apps import apps

#############   USER  #############

# 自定义用户管理器
class SysUserManager(BaseUserManager):
    def create_user(self, username, email=None, password=None, **extra_fields):
        """创建普通用户"""
        if not username:
            raise ValueError('用户名不能为空')
        user = self.model(username=username, email=email, **extra_fields)
        user.password = make_password(password)  # 使用Django的密码加密方法
        user.save(using=self._db)
        return user
    
    def create_superuser(self, username, email=None, password=None, **extra_fields):
        """创建超级用户"""
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        
        if extra_fields.get('is_staff') is not True:
            raise ValueError('超级用户必须设置is_staff=True')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('超级用户必须设置is_superuser=True')
        return self.create_user(username, email, password, **extra_fields)

# 用户表 - 继承自AbstractBaseUser和PermissionsMixin
class SysUser(AbstractBaseUser, PermissionsMixin):
    id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=100, unique=True, verbose_name="用户名")
    nick_name = models.CharField(max_length=100, null=True, blank=True, verbose_name="昵称-显示名称")
    email = models.CharField(max_length=100, null=True, blank=True, verbose_name="用户邮箱")
    avatar = models.CharField(max_length=255, null=True, verbose_name="用户头像", default="default.jpg") 
    phonenumber = models.CharField(max_length=11, null=True, blank=True, verbose_name="手机号码")
    create_time = models.DateTimeField(null=True, auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(null=True, verbose_name="更新时间")
    remark = models.CharField(max_length=500, null=True, blank=True, verbose_name="备注")
    
    # Django用户模型所需的字段
    is_staff = models.BooleanField(default=False, verbose_name="是否为管理员")
    is_active = models.BooleanField(default=True, verbose_name="是否激活")
    date_joined = models.DateTimeField(auto_now_add=True, verbose_name="注册时间")
    last_login = models.DateTimeField(null=True, blank=True, verbose_name="最后登录时间")
    user_from = models.IntegerField(choices=((1, '本地'),
                                        (2, 'LDAP')), default=1, verbose_name="用户来源")
    
    # 使用自定义管理器
    objects = SysUserManager()
    
    # 设置USERNAME_FIELD为'username'，这是用于登录的字段
    USERNAME_FIELD = 'username'
    # 创建超级用户时必须填写的字段
    REQUIRED_FIELDS = []

    @override
    def save(self, *args, **kwargs):
        self.update_time = timezone.now()
        return super().save(*args, **kwargs)

    class Meta:
        db_table = "sys_user"
        verbose_name = "sys_user"
        verbose_name_plural = verbose_name
        swappable = 'AUTH_USER_MODEL'

    def __str__(self):
        return self.username


#############   MENU  #############  
class SysMenu(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50, unique=True, verbose_name="菜单名称")
    icon = models.CharField(max_length=100, null=True, blank=True, verbose_name="菜单图标")
    parent_id = models.IntegerField(null=True, verbose_name="父菜单ID")
    order_num = models.IntegerField(null=True, verbose_name="显示顺序")
    api_path = models.CharField(max_length=255, null=True, blank=True, default='', verbose_name="API路径", help_text="后端API路径")
    path = models.CharField(max_length=200, null=True, blank=True, verbose_name="前端组件路径", help_text="前端组件路径")
    menu_type = models.CharField(max_length=1, null=True, verbose_name="菜单类型(M目录 C菜单 F按钮)")
    perms = models.CharField(max_length=100, null=True, blank=True, verbose_name="权限标识", help_text="用于按钮的权限控制")
    create_time = models.DateTimeField(null=True, verbose_name="创建时间", )
    update_time = models.DateTimeField(null=True, verbose_name="更新时间")
    remark = models.CharField(max_length=500, null=True, blank=True, verbose_name="备注")

    def __lt__(self, other):
        return self.order_num < other.order_num

    class Meta:
        db_table = "sys_menu"
        verbose_name = "sys_menu"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.id:
            self.create_time = timezone.now()
        self.update_time = timezone.now()

        if not self.parent_id:
            self.parent_id = 0

        super().save(*args, **kwargs)


# 系统角色菜单关联类
class SysRoleMenu(models.Model):
    id = models.AutoField(primary_key=True)
    role = models.ForeignKey("SysRole", on_delete=models.PROTECT)
    menu = models.ForeignKey(SysMenu, on_delete=models.PROTECT)

    class Meta:
        db_table = "sys_role_menu"
        verbose_name = "sys_role_menu"

    def __str__(self):
        return self.role.name + '-' + self.menu.name


#############  ROLE  #############  
class SysRole(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, null=True, verbose_name="角色名称")
    code = models.CharField(max_length=100, null=True, verbose_name="角色代码")
    create_time = models.DateTimeField(null=True, verbose_name="创建时间")
    update_time = models.DateTimeField(null=True, verbose_name="更新时间")
    remark = models.CharField(max_length=500, null=True, blank=True,verbose_name="备注")

    class Meta:
        db_table = "sys_role"
        verbose_name = "sys_role"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.id:
            self.create_time = timezone.now()
        self.update_time = timezone.now()
        super().save(*args, **kwargs)


class SysUserRole(models.Model):
    id = models.AutoField(primary_key=True)
    role = models.ForeignKey(SysRole, on_delete=models.CASCADE, verbose_name="角色")
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name="用户")
    
    class Meta:
        db_table = "sys_user_role"
        verbose_name = "sys_user_role"
        
    def __str__(self):
        return self.role.name + '-' + self.user.username

############### CONFIG ###############
class SysConfig(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, null=True, verbose_name="配置名称")
    json_value = models.JSONField(null=True, verbose_name="Json配置值")
    create_time = models.DateTimeField(null=True, verbose_name="创建时间")
    update_time = models.DateTimeField(null=True, verbose_name="更新时间")
    remark = models.CharField(max_length=500, null=True, blank=True,verbose_name="备注")

    class Meta:
        db_table = "sys_config"
        verbose_name = "sys_config"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.id:
            self.create_time = timezone.now()
        self.update_time = timezone.now()
        super().save(*args, **kwargs)



###############  Audit LOG ###############
# 在 system/models.py 中添加

class SysOperLog(models.Model):
    """操作日志记录"""
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name="模块标题")
    business_type = models.IntegerField(choices=(
        (0, "其他"),
        (1, "新增"),
        (2, "修改"),
        (3, "删除"),
        (4, "授权"),
        (5, "导出"),
        (6, "导入"),
        (7, "强退"),
        (8, "生成代码"),
        (9, "清空数据"),
    ), default=0, verbose_name="业务类型")
    method = models.CharField(max_length=10, verbose_name="请求方式")
    request_method = models.CharField(max_length=200, verbose_name="请求方法")
    operator_type = models.IntegerField(choices=(
        (0, "其他"),
        (1, "后台用户"),
        (2, "手机端用户"),
    ), default=0, verbose_name="操作类别")
    oper_name = models.CharField(max_length=50, verbose_name="操作人员")
    dept_name = models.CharField(max_length=50, blank=True, null=True, verbose_name="部门名称")
    oper_url = models.CharField(max_length=255, verbose_name="请求URL")
    oper_ip = models.CharField(max_length=128, verbose_name="主机地址")
    oper_location = models.CharField(max_length=255, blank=True, null=True, verbose_name="操作地点")
    oper_param = models.TextField(verbose_name="请求参数")
    json_result = models.TextField(blank=True, null=True, verbose_name="返回参数")
    status = models.IntegerField(choices=((0, "正常"), (1, "异常")), default=0, verbose_name="操作状态")
    error_msg = models.TextField(blank=True, null=True, verbose_name="错误消息")
    oper_time = models.DateTimeField(auto_now_add=True, verbose_name="操作时间")

    class Meta:
        db_table = "sys_oper_log"
        verbose_name = "操作日志记录"
        verbose_name_plural = verbose_name
        ordering = ['-oper_time']

# 全局限流模块
class SysLimit(models.Model):
    id = models.AutoField(primary_key=True)
    # user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="用户")
    ip = models.CharField(max_length=20, verbose_name="IP地址")
    limit_key = models.CharField(max_length=255, verbose_name="限制键,比如login、全局资源搜索等")
    count = models.IntegerField(verbose_name="访问次数")
    last_visit = models.DateTimeField(verbose_name="最后访问时间")
    username = models.CharField(max_length=150, null=True, blank=True, verbose_name="用户名")
    is_locked = models.BooleanField(default=False, verbose_name="是否锁定")
    locked_until = models.DateTimeField(null=True, blank=True, verbose_name="锁定截止时间")
    
    class Meta:
        db_table = "sys_limit"
        verbose_name = "sys_limit"
        verbose_name_plural = verbose_name
        indexes = [
            models.Index(fields=['username', 'limit_key']),
            models.Index(fields=['ip', 'limit_key']),
        ]

################### CORE MODEL ###################
class SoftDeleteModel(models.Model):
    is_delete = models.BooleanField(default=False, verbose_name="删除标记", help_text="删除标记")
    del_reson = models.CharField(max_length=255, null=True, blank=True, help_text="删除原因")

    def delete(self, using=None, soft_delete=True, *args, **kwargs):
        if soft_delete:
            self.is_delete = True
            self.save(using=using)
            # 级联软删除关联对象
            for related_object in self._meta.related_objects:
                related_model = getattr(self, related_object.get_accessor_name())
                if related_object.one_to_many or related_object.many_to_many:
                    related_objects = related_model.all()
                elif related_object.one_to_one:
                    related_objects = [related_model]
                else:
                    continue

                for obj in related_objects:
                    obj.delete(soft_delete=True)
        else:
            super().delete(*args, **kwargs)
        

class CoreModel(models.Model):
    """
    Core model for common fields
    """
    id = models.AutoField(primary_key=True, verbose_name="Id", help_text="Id")
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="%(app_label)s_%(class)s_creator", 
                                on_delete=models.DO_NOTHING, verbose_name="创建人", help_text="创建人")
    updater = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="%(app_label)s_%(class)s_updater", 
                                on_delete=models.DO_NOTHING, verbose_name="更新人", help_text="更新人")
    description = models.CharField(max_length=255, null=True, blank=True, help_text="描述")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间", help_text="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间", help_text="更新时间")

    class Meta:
        abstract = True
        verbose_name = "核心模型"
        verbose_name_plural = verbose_name

    exclude_fields = ['creator', 'updater', 'create_time', 'update_time', 'is_delete']
    
    def get_exclude_fields(self):
        return self.exclude_fields

    def get_all_fields(self):
        return self._meta.get_fields()
        
    def get_all_fields_names(self):
        return [field.name for field in self.get_all_fields() if field.name not in self.get_exclude_fields()]

    def get_all_fields_with_exclude(self):
        return [field.name for field in self.get_all_fields() if field.name in self.get_exclude_fields()]

    def to_dict(self):
        return {field.name: getattr(self, field.name) for field in self.get_all_fields_with_exclude()}


def get_all_models_objects(model_name=None):
    """
    获取所有模型对象
    """
    all_models = apps.get_models()
    for item in list(all_models):
        table = {"tableName": item._meta.verbose_name}
